<?php
/**
 * base Kit class
 *
 * This file is part of Webappkit, a packages system for PHP web apps
 * @link http://webappkit.net
 * @package webappkit
 * @author J.Ducastel <nospam0@ducastel.name>
 * @license http://opensource.org/licenses/gpl-license.php GNU Public License
 */

class WakKit implements iWakKit {
    /**
     * @var string kit unique id
     */
    protected $_id;

    /**
     * @var WakKitCfg kit configuration data
     */
    protected $_cfg;

    /**
     * @var string physical path
     */
    protected $_path;

    /**
     * getter for tools. autoload tools when required
     * @param string $name
     * @return WakTool
     */
    public function & __get($name) {
        if (substr($name,0,1)!='_'
        and !isset($this->$name)
        and $class=$this->_cfg->getToolClass($name)) {
            $this->_buildTool($name,$class);
        }
        return $this->$name;
    }

    /**
     * constructor
     * @access private
     * @param string kit id
     * @todo do not build tools, use lazy loading with __get instead
     */
    function __construct($id) {
        // setting config
        $this->_id=$id;
        $this->_path=webappkit::getPathFromId($id);
        $this->_cfg=webappkit::getCfgFromId($id);
        // setting tool members
        // deported to __get for lazy loading
        /*foreach ($this->_cfg['tools'] as $name => $class) {
            $this->_buildTool($name,$class);
        }*/
    }

    /**
     * this method is the one to be implemented and used for requests handling kits
     * @access public
     * @return bool
     */
    public function run() {
        throw new WakNotImplemented('kit '.$this->getId().' is not able to handle requests. method run() not implemented.');
        return false;
    }

    /**
     * get kit's path
     * @return string
     */
    public function getPath() {
        return $this->_path;
    }

    /**
     * get kit's id
     */
    public function getId() {
        return $this->_id;
    }

    /**
     * get kit's config
     * @return array
     */
    public function getCfg($key=null) {
        return $this->_cfg;
    }

    /**
     * list subkits
     * @access public
     * @return array kits ids
     */
    function listSubkits() {
        return Webappkit::listKits($this->getPath());
    }

    /**
     * get a subkit instance if available
     * @access public
     * @param string subkit id (without the parent part)
     * @return Webappkit
     */
    function getSubkit($id) {
        return Webappkit::getKit($this->getId().'.'.$id);
    }

    /**
     * get kit tools.
     * May filter by class
     * @access public
     * @param string $of_class if provided, will return only tools from this class
     * @return array name=>instance
     */
    public function & getTools($of_class=null) {
        $tools=array();
        // listing tool members
        foreach ($this->_cfg->getTools() as $name => $class) {
            // filtering if required
            if ($of_class and $of_class!=$class)
                continue;
            $tools[$name]=&$this->$name;
        }
        return $tools;
    }

    /**
     * tells if a tool has its custom config
     * @access public
     * @param string $tool tool's name
     * @return bool
     */
    public function toolHasConfig($tool) {
        $file=$this->getPath().$tool.'.tool.ini'; // echo $file;
        return file_exists($file) and is_file($file);
    }

    /**
    * loads tool's config ini file ( {name}.tool.ini )
    * @access protected
    * @param string $name tool's name
    * @return array|null|false
    */
    protected function _getToolCfg($name) {
        // getting ini file
        $file=$this->getPath().$name.'.tool.ini'; // echo $file;
        if (!file_exists($file) or !is_file($file)) {
            return null;
        }
        // parsing, with sections
        $cfg=parse_ini_file($file,true);
        if (!is_array($cfg)) {
            //trigger_error("failed to parse $file");
            throw new WakBadCfg("failed to parse $file",500);
            return false;
        }
        return $cfg;
    }

    /**
     * builds a tool member : create a tool member instance for the kit.
     * Will try to load config from ini file
     * @access protected
     * @param string $name the member name given to tool
     * @param string $class
     * @return bool
     */
    protected function _buildTool($name,$class) {
        // defining class
        if (!class_exists($class)) {
            throw new WakMissingClass("failed to build tool $name for kit {$this->_id} : class $class is missing");
            return false;
        }
        // trying to read config from ini file within self kit
        $cfg=$this->_getToolCfg($name);
        // calling factory method
            // $instance=$class::factory($this,$name);
        $instance=call_user_func(array($class,'toolFactory'),$this->getId(),$cfg);
        $this->$name=$instance;
        return true;
    }
}
